package action.back;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;

import utils.FileUtils;
import utils.SqlUtils;
import config.Constant;
import freemarker.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;

public class CodeAction {

	private static final Log logger = LogFactory.getLog(CodeAction.class);

	@Autowired
	private JdbcTemplate jdbcTemplate;

	/**
	 * Code!gen.action
	 * 
	 * @return
	 * @throws Exception 
	 */
	public String gen() throws Exception {

		List<String> tableList = SqlUtils.getTables("mysql");

		genCode(getTemplate("action/back/action.ftl"), tableList,
				Constant.CONFIG_PATH + "codes\\actions\\", "Action", ".java");
		
		genCode(getTemplate("action/back/model.ftl"), tableList,
				Constant.CONFIG_PATH + "codes\\models\\", "", ".java");
		
		genCode(getTemplate("action/back/edit.ftl"), tableList,
				Constant.CONFIG_PATH + "codes\\jsp\\", "-edit", ".jsp");
		
		genCode(getTemplate("action/back/show-jsp.ftl"), tableList,
				Constant.CONFIG_PATH + "codes\\jsp\\", "-show", ".jsp");
		
		genCode(getTemplate("action/back/list-jsp.ftl"), tableList,
				Constant.CONFIG_PATH + "codes\\jsp\\", "-list", ".jsp");

		
		genCode(getTemplate("action/back/index-jsp.ftl"), tableList,
				Constant.CONFIG_PATH + "codes\\jsp\\", "-index", ".jsp");
		
		genCode(getTemplate("action/back/index-js.ftl"), tableList,
				Constant.CONFIG_PATH + "codes\\jsp\\", "-index", ".js");
		
		return "msg";
	}

	/**
	 * Generate Template File
	 * 
	 * @param template
	 * @param tableList
	 * @param genDir
	 * @param fileNameSufix
	 * @param fileExt
	 * @throws IOException 
	 * @throws Exception 
	 */
	private void genCode(Template template,List<String> tableList, String genDir,String fileNameSufix,String fileExt) throws Exception {
		
		FileUtils.checkDir(genDir);

		for (String tableName : tableList) {
				
			String sql = "select * from " + tableName;
			SqlRowSet  rs_ = jdbcTemplate.queryForRowSet(sql);
			SqlRowSetMetaData rsmd = rs_.getMetaData();
				
				
			Map<String, Object> returnMap = new HashMap<String, Object>();
			String modelName = tableNameToClassName(tableName);
				
			returnMap.put("tableName", tableName);
			returnMap.put("ModelName", modelName);
			returnMap.put("modelName", lowerCase1(modelName));
				
			List<Map<String, String>> columns = new ArrayList<Map<String, String>>();

			for (int i = 1; i <= rsmd.getColumnCount(); i++) {

				Map<String, String> itemMap = new HashMap<String, String>();

				String type = rsmd.getColumnTypeName(i);
				String columnName = rsmd.getColumnName(i);
				String propertyName = columnNameToPropertyName(columnName);
				String sid = "Column";
				if (type.trim().equalsIgnoreCase("int"))
					type = "Integer";
				else if (type.trim().equalsIgnoreCase("date"))
					type = "Date";
				else if (type.trim().equalsIgnoreCase("datetime"))
					type = "Date";
				else if (type.trim().equalsIgnoreCase("int identity")) {
					type = "Integer";
					sid = "Id";
				} else
					type = "String";

				if (rsmd.getColumnName(i).equalsIgnoreCase("id"))
					sid = "Id";
				itemMap.put("sid", sid);
				itemMap.put("columnType", type);
					
				itemMap.put("propertyName", propertyName);
				itemMap.put("PropertyName", upperCase1(propertyName));
					
				if(sid.equals("Id"))continue;
				
				columns.add(itemMap);
			}
				
			returnMap.put("columns", columns);
				
			StringWriter writer = new StringWriter();
			template.process(returnMap, writer);
			String codeStr = writer.toString();
				
				
				
			String filepath = genDir + modelName + fileNameSufix +  fileExt;
			FileUtils.writeTextToFile(filepath, codeStr);
			logger.info(">>Write to File:" + filepath);
		}
	}

	/**
	 * Freemarker Template
	 * 
	 * @param tempStr
	 * @return
	 */
	private Template getTemplate(String tempStr) {
		try {
			InputStream in = super.getClass().getClassLoader()
					.getResourceAsStream(tempStr);
			String templateStr;
			templateStr = FileUtils.streamToString(in);
			Configuration cfg = new Configuration();
			cfg.setTemplateLoader(new StringTemplateLoader(templateStr));
			Template template = cfg.getTemplate("");
			return template;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * lowerCase first character.
	 * 
	 * @param src
	 * @return
	 */
	public static String lowerCase1(String src) {
		StringBuilder sb = new StringBuilder();

		sb.append(Character.toLowerCase(src.charAt(0)));
		sb.append(src.substring(1));
		return sb.toString();
	}

	/**
	 * upperCase first character.
	 * 
	 * @param src
	 * @return
	 */
	public static String upperCase1(String src) {
		StringBuilder sb = new StringBuilder();

		sb.append(Character.toUpperCase(src.charAt(0)));
		sb.append(src.substring(1));
		return sb.toString();
	}

	/**
	 * columnName to propertyName
	 * 
	 * @param src
	 * @return
	 */
	public static String columnNameToPropertyName(String src) {

		StringBuilder sb = new StringBuilder();
		sb.append(Character.toUpperCase(src.charAt(0)));

		for (int i = 1; i < src.length(); i++) {
			if (src.charAt(i) == '_') {
				sb.append(Character.toUpperCase(src.charAt(++i)));
			} else {
				sb.append(src.charAt(i));
			}
		}

		return lowerCase1(sb.toString());
	}

	/**
	 * tableName to className
	 * 
	 * @param src
	 * @return
	 */
	public static String tableNameToClassName(String src) {

		StringBuilder sb = new StringBuilder();
		sb.append(Character.toUpperCase(src.charAt(0)));

		for (int i = 1; i < src.length(); i++) {
			if (src.charAt(i) == '_') {
				sb.append(Character.toUpperCase(src.charAt(++i)));
			} else {
				sb.append(src.charAt(i));
			}
		}

		return sb.toString();
	}
}
